<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
    <script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>
    <meta charset="UTF-8">
<meta name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">

    <meta name="author" content="Horace">




    <meta name="keywords" content="zhaohaihao,赵海豪,海豪,Horace,Horace's Blog,海豪的博客,Java,后端">



    <title>设计模式之设计原则-单一职责原则 (SRP) | Horace&#39;s Blog</title>
    



    <link rel="icon" href="/favicon.ico">




    <!-- stylesheets list from _config.yml -->
    
    <link rel="stylesheet" href="/css/style.css">
    



    <!-- scripts list from _config.yml -->
    
    <script src="/js/script.js"></script>
    
    <script src="/js/tocbot.min.js"></script>
    
    <script src="/js/custom.js"></script>
    



    
    
        
    


    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<meta name="generator" content="Hexo 4.2.0"><link rel="alternate" href="/atom.xml" title="Horace" type="application/atom+xml">
</head>
<body>
	<script type="text/javascript" src="/js/canvas-colorful-nest.js"></script>
    <div class="wrapper">
        <header>
    
        <nav class="navbar">
            <div class="container">
                <div class="navbar-header header-logo"><a href="/">Horace&#39;s Blog</a></div>
                <div class="menu navbar-right">
                    
                        <a class="menu-item" href="/archives">归档</a>
                    
                        <a class="menu-item" href="/categories">分类</a>
                    
                        <a class="menu-item" href="/tags">标签</a>
                    
                        <a class="menu-item" href="/links">友链</a>
                    
                        <a class="menu-item" href="/about">关于</a>
                    
                    <input id="switch_default" type="checkbox" class="switch_default">
                    <label for="switch_default" class="toggleBtn"></label>
                </div>
            </div>
        </nav>

        
        <nav class="navbar-mobile" id="nav-mobile">
            <div class="container">
                <div class="navbar-header">
                    <div>
                        <a href="/">Horace&#39;s Blog</a>
                    </div>
                    <div style="display: inherit;">
                        <div><a id="mobile-toggle-theme">Light</a></div>
                        <div class="menu-toggle" onclick="mobileBtn()" style="padding-left: 15px;">&#9776;菜单</div>
                    </div>
                    
                </div>
                <div class="menu" id="mobile-menu">
                    
                        <a class="menu-item" href="/archives">归档</a>
                    
                        <a class="menu-item" href="/categories">分类</a>
                    
                        <a class="menu-item" href="/tags">标签</a>
                    
                        <a class="menu-item" href="/links">友链</a>
                    
                        <a class="menu-item" href="/about">关于</a>
                    
                </div>
            </div>
        </nav>
    
</header>
<script>
    var mobileBtn = function f() {
        var toggleMenu = document.getElementsByClassName("menu-toggle")[0];
        var mobileMenu = document.getElementById("mobile-menu");
        if(toggleMenu.classList.contains("active")){
           toggleMenu.classList.remove("active")
           mobileMenu.classList.remove("active")
        }else{
           toggleMenu.classList.add("active")
           mobileMenu.classList.add("active")
        }
    }
</script>
        <div class="main">
            <div class="container">
    
    
        <div class="post-toc">
    <div class="tocbot-list">
    </div>
    <div class="tocbot-list-menu">
        <!--<a class="tocbot-toc-expand" onclick="expand_toc()">Expand all</a>
        <a onclick="go_top()">Back to top</a>
        <a onclick="go_bottom()">Go to bottom</a>-->
        <a onclick="go_top()">返回页首</a>
        <a onclick="go_bottom()">转到底部</a>
    </div>
</div>

<script>
    document.ready(
        function () {
            tocbot.init({
                tocSelector: '.tocbot-list',
                contentSelector: '.post-content',
                headingSelector: 'h1, h2, h3, h4, h5',
                collapseDepth: 1,
                orderedList: false,
                scrollSmooth: true,
            })
        }
    )

    function expand_toc() {
        var b = document.querySelector(".tocbot-toc-expand");
        tocbot.init({
            tocSelector: '.tocbot-list',
            contentSelector: '.post-content',
            headingSelector: 'h1, h2, h3, h4, h5',
            collapseDepth: 6,
            orderedList: false,
            scrollSmooth: true,
        });
        b.setAttribute("onclick", "collapse_toc()");
        b.innerHTML = "Collapse all"
    }

    function collapse_toc() {
        var b = document.querySelector(".tocbot-toc-expand");
        tocbot.init({
            tocSelector: '.tocbot-list',
            contentSelector: '.post-content',
            headingSelector: 'h1, h2, h3, h4, h5',
            collapseDepth: 1,
            orderedList: false,
            scrollSmooth: true,
        });
        b.setAttribute("onclick", "expand_toc()");
        b.innerHTML = "Expand all"
    }

    function go_top() {
        window.scrollTo(0, 0);
    }

    function go_bottom() {
        window.scrollTo(0, document.body.scrollHeight);
    }

</script>
    

    
    <article class="post-wrap">
        <header class="post-header">
            <h1 class="post-title">设计模式之设计原则-单一职责原则 (SRP)</h1>
            
                <div class="post-meta">
                    <i class="iconfont icon-calendar"></i> 发表于 2020-02-05
                    &nbsp;|&nbsp;
                    
                        <span class="post-category">
                        <i class="iconfont icon-folder"></i> 分类于 
                            
                                <a href="/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"> 设计模式</a>
                            
                        </span>
                    &nbsp;|&nbsp;
                    
                    <span id="busuanzi_container_page_pv">
                    <i class="iconfont icon-eye"></i> 阅读量 <span id="busuanzi_value_page_pv"></span> 次
                    </span>

                    <!-- | 
                    2k 字
                     |
                    7 分钟
                    -->
                <!--
                    
                        <a itemprop="author" rel="author" href="/">Horace</a> 
                    

                    
                        <span class="post-time">
                        发布于 <a href="#">02-05&nbsp;16:15:11</a> ,
                        </span>
                    
                    
                        <span class="post-category">
                            
                                <a href="/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"># 设计模式</a>
                            
                        </span>
                    
                -->
                </div>
            
        </header>

        <div class="post-content">
            <p><a href="https://emojipedia.org/backhand-index-pointing-right/" target="_blank" rel="noopener">👉</a><a href="https://github.com/zhaohaihao/java-design-patterns/tree/master/003-SRP" target="_blank" rel="noopener"><strong>文章示例代码</strong></a><a href="https://emojipedia.org/backhand-index-pointing-left/" target="_blank" rel="noopener">👈</a></p>
<h1 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h1><blockquote>
<p>就一个类而言，有且仅有一个引起它变更的原因。</p>
</blockquote>
<p>一个类/接口/方法只负责一项职责。</p>
<h2 id="如何理解"><a href="#如何理解" class="headerlink" title="如何理解"></a>如何理解</h2><p>假设有个 A 类负责职责1和职责2两个职责。</p>
<p>当需求发生变更时，比方说职责1相关的功能需要发生改变，那我们在修改 A 这个类的时候就有可能会导致原本运行正常的职责2发生故障。</p>
<p>也就是说对于这个 A 类来说，当职责1和职责2的需求发生变化时候，都会影响这个 A 类，即存在两个导致类变更的原因。</p>
<h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>遵循单一职责原则，针对上述职责1和职责2建立 A 类和 B 类，分别负责职责1和职责2。</p>
<p>这种情况下，当我们在修改 A 类的时候，对于负责职责2的 B 类来说是不会发生变更的，也不会使其发生故障，反之亦然。</p>
<h1 id="场景示例"><a href="#场景示例" class="headerlink" title="场景示例"></a>场景示例</h1><p>笔者这里用饮料归类做个示范来帮助理解。</p>
<h2 id="创建饮料类"><a href="#创建饮料类" class="headerlink" title="创建饮料类"></a>创建饮料类</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 饮料类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:23</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Drink</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 饮料类型</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> drinkName 饮料名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">type</span><span class="params">(String drinkName)</span> </span>&#123;</span><br><span class="line">        System.out.println(drinkName + <span class="string">"是汽水"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="测试类及输出"><a href="#测试类及输出" class="headerlink" title="测试类及输出"></a>测试类及输出</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 测试类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:25</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Drink drink = <span class="keyword">new</span> Drink();</span><br><span class="line">        drink.type(<span class="string">"可乐"</span>);</span><br><span class="line">        drink.type(<span class="string">"牛奶"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试类的输出结果如下：</p>
<blockquote>
<p>可乐是汽水<br>牛奶是汽水</p>
</blockquote>
<h1 id="方案调整"><a href="#方案调整" class="headerlink" title="方案调整"></a>方案调整</h1><p>在上述的场景示例当中我们可以看到，<strong>牛奶是汽水</strong>这答案显然是不对的。</p>
<p>为了解决这个问题，我们也许会这样做，在原来饮料类的饮料类型方法中增加一个分支判断。代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Drink</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 饮料类型</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> drinkName 饮料名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">type</span><span class="params">(String drinkName)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="string">"牛奶"</span>.equals(drinkName)) &#123;</span><br><span class="line">            System.out.println(drinkName + <span class="string">"是奶制品"</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            System.out.println(drinkName + <span class="string">"是汽水"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述方案调整看似解决了这个问题。</p>
<p>但是我们不妨再想想，如果在这个地方我们再传入一些其他的饮料(既不是奶制品也不是汽水)，那么我们的这个饮料类型方法可能还需要继续去扩展，即需要不断地调整变更这个方法，这样是不遵循单一职责原则的。</p>
<h2 id="职责分离"><a href="#职责分离" class="headerlink" title="职责分离"></a>职责分离</h2><p>换种方式，这里我们按照类来进行职责分离，使得每个类中的职责单一。代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 汽水饮料</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:34</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SodaDrink</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 饮料类型</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> drinkName 饮料名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">type</span><span class="params">(String drinkName)</span> </span>&#123;</span><br><span class="line">        System.out.println(drinkName + <span class="string">"是汽水"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 奶制品饮料</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:34</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DairyDrink</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 饮料类型</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> drinkName 饮料名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">type</span><span class="params">(String drinkName)</span> </span>&#123;</span><br><span class="line">        System.out.println(drinkName + <span class="string">"是奶制品"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>对应的测试类调整</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SodaDrink sodaDrink = <span class="keyword">new</span> SodaDrink();</span><br><span class="line">        sodaDrink.type(<span class="string">"可乐"</span>);</span><br><span class="line"></span><br><span class="line">        DairyDrink dairyDrink = <span class="keyword">new</span> DairyDrink();</span><br><span class="line">        dairyDrink.type(<span class="string">"牛奶"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="类结构图"><a href="#类结构图" class="headerlink" title="类结构图"></a>类结构图</h2><p>以上示例类的结构图如下所示</p>
<p><img src="https://oss.zhaohaihao.com/photo/design-patterns/srp/srp01.png?x-oss-process=style/style01" alt="image.png"></p>
<h1 id="其余方式"><a href="#其余方式" class="headerlink" title="其余方式"></a>其余方式</h1><p>以上方案调整是按类的职责分离实现的。我们看看其他两种方式是如何实现职责分离的。</p>
<h2 id="接口方式"><a href="#接口方式" class="headerlink" title="接口方式"></a>接口方式</h2><p>给定一个商品接口，我们可以看到这个接口的一个职责是获取商品的信息(名称、价格)，而另一个职责可以看做是管理商品(购买、退款)，与商品内容无关。</p>
<p>在这两个职责中退款商品势必会影响这个接口中获取商品信息相关内容的变化(比方说退了商品那可能就无法获得商品的名称和价格了)，即这两个职责是互相影响的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 商品接口</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:49</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IGoods</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取商品名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">String <span class="title">getGoodsName</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取商品价格</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">Double <span class="title">getGoodsPrice</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 购买商品</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">buyGoods</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 退款商品</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">refundGoods</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="对接口按职责进行拆分"><a href="#对接口按职责进行拆分" class="headerlink" title="对接口按职责进行拆分"></a>对接口按职责进行拆分</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 商品信息接口</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:52</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IGoodsInfo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取商品名称</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">String <span class="title">getGoodsName</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取商品价格</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">Double <span class="title">getGoodsPrice</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 商品管理接口</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:53</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IGoodsManager</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 购买商品</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">buyGoods</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 退款商品</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">refundGoods</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="创建商品实现类"><a href="#创建商品实现类" class="headerlink" title="创建商品实现类"></a>创建商品实现类</h3><p>创建一个商品的具体实现类，同时实现上述按职责分离的两个接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> 商品实现类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:56</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GoodsImpl</span> <span class="keyword">implements</span> <span class="title">IGoodsManager</span>, <span class="title">IGoodsInfo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getGoodsName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"商品名称"</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Double <span class="title">getGoodsPrice</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0.0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">buyGoods</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"购买商品"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">refundGoods</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"退款商品"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="类结构图-1"><a href="#类结构图-1" class="headerlink" title="类结构图"></a>类结构图</h3><p>以上示例类的结构图如下所示</p>
<p><img src="https://oss.zhaohaihao.com/photo/design-patterns/srp/srp02.png?x-oss-process=style/style01" alt="image.png"></p>
<h2 id="方法方式"><a href="#方法方式" class="headerlink" title="方法方式"></a>方法方式</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhh</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-02-05 22:59</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Method</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 更新商品信息</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> goodsName  商品名称</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> goodsPrice 商品价格</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">updateGoodsInfo</span><span class="params">(String goodsName, Double goodsPrice)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 模拟更新商品名称、价格</span></span><br><span class="line">        goodsName = <span class="string">"可乐"</span>;</span><br><span class="line">        goodsPrice = <span class="number">3.0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以看到上面这个方法又是更新商品的名称，又是更新商品的价格。</p>
<p>然而按照方法方式进行职责分离应该是以下这种样式。代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Method</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">updateGoodsName</span><span class="params">(String goodsName)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 模拟更新商品名称</span></span><br><span class="line">        goodsName = <span class="string">"可乐"</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">updateGoodsPrice</span><span class="params">(Double goodsPrice)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 模拟更新商品价格</span></span><br><span class="line">        goodsPrice = <span class="number">3.0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>即我们把刚才的方法拆解成两个方法。</p>
<p>要修改商品的名称只要调用修改商品名称的方法即可，要修改商品的价格只要调用修改商品价格的方法即可。</p>
<p>这两个方法的职责是非常单一且清晰的。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>单一职责原则的核心就是控制类的粒度的大小，将对象进行解耦，提高其内聚性。</p>
<h2 id="职责分离条件"><a href="#职责分离条件" class="headerlink" title="职责分离条件"></a>职责分离条件</h2><blockquote>
<p>能够想到多于一个的动机去改变一个类，那么这个类就具有多于一个的职责，就可以考虑类的职责分离。</p>
</blockquote>
<p>整合虽然说是一种很好的思维方式，但是在软件设计的时候，我们应该在类的职责分离上多做思考，尽量让每个类保持单一职责。但是由于每个人的看法不一，这就会导致职责边界的难以划分。有时候我们也需要做出相应的妥协，并不能完全死套单一职责原则，否则就会冗余出非常多的类文件，给维护带来不便。</p>
<p>单一职责不仅针对类来说，同样也适用于方法。一个方法应该尽可能地做好一件事情(只负责一项职责)。如果一个方法处理的事情过多(承担的职责过多)，其颗粒度会变得很粗，从而不利于重用。</p>
<h2 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h2><ul>
<li>降低类的复杂度。一个类只需要去负责一项职责，逻辑相对于负责多项职责的类来说要简单的多。</li>
<li>提高类的可读性。复杂度的降低，其可读性自然会提高。</li>
<li>提高系统的可维护性。可读性的提高，使得系统更容易维护。</li>
<li>降低变更引起的风险。变更是必然的，如果单一职责原则遵守得好，当修改一个功能时，可以显著降低对其他功能的影响。</li>
</ul>
<h2 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h2><ul>
<li>如果一个类承担的职责过多(等同于将这些职责耦合在一起)，一个职责的变化可能会削弱或者抑制这个类去完成其他职责的能力，这种耦合会导致设计的脆弱。</li>
<li>一个类如果承担过多的职责，当客户端需要该类的某一项职责的时候，不得不将其他不需要的职责全部包含进来，从而造成冗余的代码或者代码的浪费。</li>
</ul>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>《Head First 设计模式》</li>
<li>《大话设计模式》</li>
</ul>

        </div>

        
            <section class="post-copyright">
            
                
                
                
                

                
                    <p class="copyright-item" style="text-align: center; margin: 20px 0px;">
                        <span>© 转载请保留本文地址, 著作权归作者所有</span>
                    </p>
                

            </section>
        
        <section class="post-tags">
            <div>
                <!--<span>Tag(s):</span>-->
                <span class="tag">
                    
                    
                      <i class="iconfont icon-tag"></i> <a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">设计模式</a>
                    
                        
                </span>
            </div>
            <div>
                <a href="javascript:window.history.back();">返回上层</a>
                <span>· </span>
                <a href="/">返回主页</a>
            </div>
        </section>
        <section class="post-nav">
            
                <a class="prev" rel="prev" href="/posts/2020020601.html">设计模式之设计原则-接口隔离原则 (ISP)</a>
            
            
            <a class="next" rel="next" href="/posts/2020020502.html">设计模式之设计原则-依赖倒置原则 (DIP)</a>
            
        </section>


    </article>
</div>

        </div>
        
	<footer id="footer" class="footer" style="line-height: unset;">
	    <div class="copyright" style="text-align: center;">
	        本站已安全运行 <span id="htmer_time">0年293天1时59分51秒</span></br>
            <span id="busuanzi_container_site_pv">总访问量 <span id="busuanzi_value_site_pv"></span> 次</span>
            |
            <span id="busuanzi_container_site_uv">总访客数 <span id="busuanzi_value_site_uv"></span> 人</span>
            |
            总字数 42.7k 字  <a href="https://zhaohaihao.com/atom.xml" target="_blank"><i class="iconfont icon-RSS"></i></a> </br>
	        <span>© 2019-2020 Horace&#39;s Blog.</span> <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow">浙ICP备18055264号</a>
	    </div>
	</footer>

    <style>
        .icon-RSS {
            color: #FD9B00;
        }
    </style>

	<script language="javascript">
    function siteTime(){
        window.setTimeout("siteTime()", 1000);
        var seconds = 1000;
        var minutes = seconds * 60;
        var hours = minutes * 60;
        var days = hours * 24;
        var years = days * 365;
        var today = new Date();
        var todayYear = today.getFullYear();
        var todayMonth = today.getMonth()+1;
        var todayDate = today.getDate();
        var todayHour = today.getHours();
        var todayMinute = today.getMinutes();
        var todaySecond = today.getSeconds();
        /* Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
        year - 作为date对象的年份，为4位年份值
        month - 0-11之间的整数，做为date对象的月份
        day - 1-31之间的整数，做为date对象的天数
        hours - 0(午夜24点)-23之间的整数，做为date对象的小时数
        minutes - 0-59之间的整数，做为date对象的分钟数
        seconds - 0-59之间的整数，做为date对象的秒数
        microseconds - 0-999之间的整数，做为date对象的毫秒数 */
        var t1 = Date.UTC(2019,6,12,22,22,22); //北京时间2016-12-1 00:00:00
        var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
        var diff = t2-t1;
        var diffYears = Math.floor(diff/years);
        var diffDays = Math.floor((diff/days)-diffYears*365);
        var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
        var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
        var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
        document.getElementById("htmer_time").innerHTML=diffYears+"年"+diffDays+"天"+diffHours+"时"+diffMinutes+"分"+diffSeconds+"秒";
    }
    siteTime();
</script>

    </div>
</body>
</html>
